package loader

//模块加载器

import (
	"fmt"
	"lark/src/ast"
	"lark/src/lib/request"
	"lark/src/object"
	"log"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

// Import 表示一个导入声明
type Import struct {
	Path string
	As   string // 可选的别名
}

// Symbol 表示命名空间中的一个符号
type Symbol struct {
	Name       string
	Type       string
	Module     *Module
	IsExported bool // 是否为导出符号
	IsComputed bool // 是否参与计算（关键标记）
}

// 表示一个模块
type Module struct {
	Path    string       // 规范化后的模块路径
	AbsPath string       // 模块文件的绝对路径
	Source  string       // 源码
	Imports []*Import    // 导入的包
	AST     *ast.Program // 抽象语法树
	// Scope   map[string]Symbol // 包的命名空间
	Scope     *object.Environment //符号表
	IsMain    bool                // 是否主模块
	Evaluated bool                // 标记是否已执行计算
	IsLibrary bool                // 是否为标准库模块
}

// 模块加载器负责查找和加载包
type ModuleLoader struct {
	searchPaths []string             // 搜索路径列表
	cache       map[string]*Module   // 已加载包的缓存
	stdLibCache map[string]StdModule // 标准库模块缓存
	mu          sync.Mutex           // 添加互斥锁保证并发安全
}

func NewModuleLoader(searchPaths []string) *ModuleLoader {
	return &ModuleLoader{
		searchPaths: searchPaths,
		cache:       make(map[string]*Module),
		stdLibCache: make(map[string]StdModule),
	}
}

// 加载脚本模块
// 加载模块并返回包信息
func (l *ModuleLoader) LoadModule(importPath string) (interface{}, error) {
	// 检查缓存
	if pkg, ok := l.cache[importPath]; ok {
		return pkg, nil
	}
	if pkg, ok := l.stdLibCache[importPath]; ok {
		return pkg, nil
	}
	// 解析导入路径为文件系统路径
	filePath, err := l.resolvePath(importPath)
	if err != nil {
		/* // 如果文件不存在，就是标准库模块
		stdLibModels := map[string]StdModule{
			"request": &request.RequestModule{}, // 标准库模块
			// "sqlite":  &sqlite.SqliteModule{},   // 标准库模块
		}
		if stdLibModel, ok := stdLibModels[importPath]; ok {
			// 注册标准库模块
			// 缓存模块
			l.stdLibCache[importPath] = stdLibModel
			return stdLibModel, nil
		} */
		return nil, err
	}

	// 读取文件内容
	source, err := os.ReadFile(filePath)
	fmt.Println("err:", err)
	if err != nil {
		return nil, err
	}

	// 创建新模块
	module := &Module{
		Path:      l.normalizePath(importPath),
		AbsPath:   filePath,
		Source:    string(source),
		Evaluated: false,
	}
	// 解析导入语句
	if err := l.parseImports(module); err != nil {
		return nil, err
	}

	/* // 词法分析
	lex := lexer.New(string(source))
	p := parser.New(lex)
	module.AST = p.ParseProgram() */

	/*
		module.Scope = l.env
		evaluator.NewEvaluator(module.Scope)
		evaluated := evaluator.Eval(program, module.Scope)
		if evaluated != nil {
			evaluated.Inspect()
			if val, ok := evaluated.(*object.Error); ok {

				fmt.Println("main.go:", val.Message)

			}
		}
	*/

	// 确定模块在当前作用域中的名称（简称）
	// 规则：取导入路径的最后一段（如./demo/test/index的简称为"index"）
	moduleAlias := l.getModuleAlias(importPath)
	// 缓存模块
	l.cache[moduleAlias] = module

	// 递归加载依赖
	for _, imp := range module.Imports {
		_, err := l.LoadModule(imp.Path)
		if err != nil {
			return nil, fmt.Errorf("failed to load dependency %s: %v", imp.Path, err)
		}
	}
	return module, nil
}

// 加载原生模块
func (l *ModuleLoader) LoadNativeModule(importPath string) (interface{}, error) {
	// 检查缓存
	if pkg, ok := l.cache[importPath]; ok {
		return pkg, nil
	}
	if pkg, ok := l.stdLibCache[importPath]; ok {
		return pkg, nil
	}
	// 解析导入路径为文件系统路径
	_, err := l.resolvePath(importPath)
	if err != nil {
		// 如果文件不存在，就是标准库模块
		stdLibModels := map[string]StdModule{
			"request": &request.RequestModule{}, // 标准库模块
			// "sqlite":  &sqlite.SqliteModule{},   // 标准库模块
		}
		if stdLibModel, ok := stdLibModels[importPath]; ok {
			// 注册标准库模块
			// 缓存模块
			l.stdLibCache[importPath] = stdLibModel
			return stdLibModel, nil
		}
	}
	return nil, err
}

// 获取模块在当前作用域中的别名（如./demo/test/index → "index"）
func (l *ModuleLoader) getModuleAlias(importPath string) string {
	// 处理绝对路径：import "tc" → "tc"
	// 处理相对路径：import "./demo/test/index" → "index"
	return filepath.Base(importPath)
}

// 规范化路径（如将./demo/test/index和demo/test/index视为同一模块）
func (l *ModuleLoader) normalizePath(importPath string) string {
	// 实际实现中需处理相对路径转正、去除冗余../等
	return filepath.Clean(importPath)
}

// 解析导入路径为文件系统路径
func (l *ModuleLoader) resolvePath(importPath string) (string, error) {
	// 1. 处理相对路径（以./或../开头）
	if filepath.IsAbs(importPath) {
		// 绝对路径（如/usr/local/modules/tc）
		return l.resolveAbsolute(importPath)
	} else if importPath[0] == '.' {
		// 相对路径（如./demo/test/index）
		return l.resolveRelative(importPath)
	} else {
		// 2. 处理绝对路径（如"tc"）
		return l.resolveGlobal(importPath)
	}

	/* // 在搜索路径中查找导入路径对应的目录
	for _, searchPath := range l.searchPaths {
		fileName := importPath + ".la"
		path := filepath.Join(searchPath, fileName)
		// 检查路径是否存在
		// 实际实现中应该使用os.Stat等函数进行检查
		if pathExists(path) {
			return path, nil
		} else {
			if pathExists(fileName) {
				return fileName, nil
			}
		}
	} */

	return "", fmt.Errorf("package %s not found in search paths", importPath)
}

// 解析绝对路径（如/usr/local/modules/tc）
func (l *ModuleLoader) resolveAbsolute(absPath string) (string, error) {
	// 检查路径是否存在，且是文件（假设模块以.la为后缀）
	targetPath := absPath
	suffix := ".la"
	// 判断后缀
	if !strings.HasSuffix(absPath, suffix) {
		//没有后缀
		targetPath = absPath + ".la"
	}
	if _, err := os.Stat(targetPath); err == nil {
		return targetPath, nil
	}
	// 尝试目录下的index.l（如import ./demo/test 可能指向./demo/test/index.l）
	dirIndexPath := filepath.Join(absPath, "index.la")
	if _, err := os.Stat(dirIndexPath); err == nil {
		return dirIndexPath, nil
	}
	return "", fmt.Errorf("absolute module %s not found", absPath)
}

// 解析相对路径（如./demo/test/index，基于当前模块目录）
func (l *ModuleLoader) resolveRelative(relPath string) (string, error) {
	// 拼接当前目录和相对路径，得到绝对路径
	absPath := filepath.Join(relPath)
	// 调用绝对路径解析逻辑
	return l.resolveAbsolute(absPath)
}

// 解析全局路径（如"tc"，从全局搜索路径查找）
func (l *ModuleLoader) resolveGlobal(globalPath string) (string, error) {
	/**
	 * 获取编译器所在目录
	 * 这里假设编译器的lib目录下有全局模块
	 * 则全局模块在D:\project\go\src\lark\lib
	 * go run . 开发时获取的时临时目录C:\Users\vteip\AppData\Local\Temp\go-build58344061\b001\exe\lib\file\index.la
	 */
	compilerDir := getExecutablePath() + "\\src\\lib"
	// 遍历全局搜索路径（如标准库目录）
	for _, base := range l.searchPaths {
		// targetPath := filepath.Join(compilerDir, globalPath) + ".la"
		// if _, err := os.Stat(targetPath); err == nil {
		// 	return targetPath, nil
		// }

		// 尝试目录下的index.l
		dirIndexPath := filepath.Join(compilerDir, globalPath, "index.la")

		if _, err := os.Stat(dirIndexPath); err == nil {
			return dirIndexPath, nil
		}
		//当前目录下
		targetPath := filepath.Join(base, globalPath) + ".la"
		if _, err := os.Stat(targetPath); err == nil {
			return targetPath, nil
		}

	}

	return "", fmt.Errorf("global module %s not found in search paths", globalPath)
}

// 区分开发和生产环境
func getExecutablePath() string {
	exe, err := os.Executable()
	if err != nil {
		log.Fatal(err)
	}

	// 开发环境处理
	if strings.Contains(exe, "go-build") {
		// 获取当前工作目录
		dir, err := os.Getwd()
		if err != nil {
			log.Fatal(err)
		}
		return dir
	}
	return filepath.Dir(exe)
}

func pathExists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return false // 其他错误（如权限不足）也视为不存在
}

// 解析包内容
// parseImports 解析模块中的导入语句
func (l *ModuleLoader) parseImports(module *Module) error {
	// 简单的词法分析，实际编译器需要更复杂的实现
	lines := strings.Split(module.Source, "\n")
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if strings.HasPrefix(line, "import ") {
			importPath := strings.Trim(line[7:], "\"; ")
			module.Imports = append(module.Imports, &Import{Path: importPath})
		}
	}
	return nil
}

// GetModule 获取已加载的模块
func (l *ModuleLoader) GetModule(name string) (interface{}, bool) {
	if mod, ok := l.cache[name]; ok {
		return mod, ok
	}
	if mod, ok := l.stdLibCache[name]; ok {
		return mod, ok
	}
	return nil, false
}
